Contents

John M. Shea

2/4/2021

Animated histogram showing outcomes dropping in (like balls dropped into tubes and piling up).

import numpy as np
import numpy.random as npr
import random
import matplotlib
import matplotlib.pyplot as plt
from matplotlib import animation
from matplotlib.animation import PillowWriter
from IPython.display import HTML

%matplotlib inline
# First simulate rolling a fair die 100 times
random.seed(288)
faces=['H','T']
num_sims=100
flips=20

results=[]
for sim in range(num_sims):              # The simulation loop
    coins=random.choices(faces, k=flips) # Simulate all coin flips for one experiment
    results+=[coins.count('H')]          # Add the number of 'H's in this experiment to our results list
# Next make the animation and render it to the screen
ymax=24
ballwidth=0.57
ballheight=1

fig = plt.figure()
fig.set_dpi(100)
fig.set_size_inches(5, 4)

ballstart=((ymax+1)//ballheight)*ballheight

ax = plt.axes(xlim=(2, 18), ylim=(0, ymax))
plt.grid(axis='y')
patches={}
floors={}
    
done=False
def gen():
    frame=0
    while not done:
        yield frame
        frame+=1
        
#pbar = tqdm(total=len(rolls))


        
    
def init():
    patches['activePatch']=0
    #for num,var in enumerate(rolls):
    num=0
    val=results[num]
    patch = matplotlib.patches.Ellipse((val+0.02, ymax+2.95), ballwidth,
                                       ballheight, fc='b')
    ax.add_patch(patch)
    patches[num]=patch
    for val in range(1,max(results)+1):
        floors[val]=ballheight*1
        #print(num,var, patches)

    return []

def animate(i, patches,rolls):
    global done, pbar
    activePatch=patches['activePatch']
    if activePatch not in patches.keys():
        print(extra)
        return []


    x,y=patches[activePatch].get_center()
    x=int(x)
    if y<=floors[x]:
        floors[x]=floors[x]+ballheight
        patches['activePatch']=activePatch+1
        activePatch+=1
        if activePatch %4 == 0:
            print("*",end="")
        #print(patches.keys())
        #print(activePatch)

        if activePatch not in patches.keys():
            if activePatch<len(results):
                val=results[activePatch]
                patch = matplotlib.patches.Ellipse((val+0.02, ymax+2.95),
                                                   ballwidth, ballheight, fc='b')
                ax.add_patch(patch)
                patches[activePatch]=patch



            else:
                print("]",end="")
                done=True
                return []
    
    patch=patches[activePatch]
    x, y = patch.get_center()

    if y>=floors[int(x)]+2*ballheight:
        y =  y-2*ballheight
    else:
        y =  y-ballheight
    patch.set_center((x, y))
    
    return[]


print("["+"="*(len(results)//4)+"]")
print("[",end="")
    
anim = animation.FuncAnimation(fig, animate, 
                               init_func=init, 
                               #frames=int((ymax/ballheight/2))*len(G40), 
                               #frames=100,
                               frames=gen,
                               save_count=int((ymax/ballheight/2))*len(results), 
                               fargs=(patches,results),
                               interval=15,
                               blit=True,repeat=False)

#Comment this out and uncomment the anim.save() to write the GIF
HTML(anim.to_jshtml())

# anim.save('ball_histogram.gif',
#             writer=PillowWriter(fps=24, bitrate=1000), dpi=200)
[=========================]
[*************************]
../_images/ball-drop-histogram-old_3_2.png
print(results)
[10, 11, 12, 13, 8, 12, 7, 14, 10, 12, 13, 15, 11, 13, 9, 9, 9, 7, 13, 6, 7, 8, 11, 9, 10, 9, 8, 10, 11, 7, 10, 8, 9, 11, 12, 12, 11, 12, 9, 10, 14, 14, 12, 9, 8, 7, 9, 10, 9, 9, 11, 11, 8, 11, 8, 4, 11, 9, 8, 9, 7, 13, 11, 10, 10, 10, 11, 12, 9, 10, 11, 8, 9, 10, 11, 9, 11, 12, 10, 9, 13, 9, 9, 10, 11, 9, 11, 10, 10, 8, 9, 11, 14, 10, 13, 10, 15, 12, 9, 9]